#include <types.h>
#include <sys_config.h>

#include <api/libtsi/si_types.h>
#include <api/libtsi/si_section.h>

#include <api/libsi/si_module.h>
#include <api/libsi/si_sdtt.h>
#include <api/libsi/si_tdt.h>


#define PP_DEBUG_LEVEL			0
#if (PP_DEBUG_LEVEL>0)
#include <api/libc/printf.h>
#define PP_PRINTF			libc_printf
#else
#define PP_PRINTF(...)			do{}while(0)
#endif

#define	SDTT_MERG_UINT16(u8_high,u8_low)		((u8_low) | (((UINT16)(u8_high))<<8))

UINT16 m_SdttChanIndex;

void st_sdtt_set_channel_index(UINT16 chanindex)
{
	m_SdttChanIndex = chanindex;
}

//Pasering Module Desc
UINT16 st_sdtt_parser_module_desc(UINT8 *module_desc)
{
	UINT16 i,module_num,total_size=0;
	struct SDTT_DL_CONT_MOD *module_desc_dat;

	module_num = SDTT_MERG_UINT16(*(module_desc+1),*module_desc);
	module_desc_dat = (struct SDTT_DL_CONT_MOD *)(module_desc+1);

	for(i=0;i<module_num;i++)
	{
		total_size += (module_desc_dat->mod_inf_len + sizeof(struct SDTT_DL_CONT_MOD));
		module_desc_dat = (struct SDTT_DL_CONT_MOD *)(((UINT8 *)module_desc_dat)+total_size);
	}

	return total_size;
}


//Pasering Compatibility Desc
UINT16 si_sdtt_parser_compab_desc(struct SDTT_COMPAB_DESC_1 *compab_desc1)
{
	struct SDTT_COMPAB_DESC_2 *compab_desc2;
	UINT16 k,CompabLen,CompabCnt;
	UINT16 module, version;
	
	compab_desc2 = (struct SDTT_COMPAB_DESC_2 *)(((UINT8 *)compab_desc1) + sizeof(struct SDTT_COMPAB_DESC_1));
	CompabLen = SDTT_MERG_UINT16(compab_desc1->desc_len_hi,compab_desc1->desc_len_lo)+2;
	CompabCnt = SDTT_MERG_UINT16(compab_desc1->desc_cnt_hi,compab_desc1->desc_cnt_lo);
	
	for(k=0;k<CompabCnt;k++)
	{
		module = SDTT_MERG_UINT16(compab_desc2->module_hi, compab_desc2->module_lo);
		version = SDTT_MERG_UINT16(compab_desc2->version_hi, compab_desc2->version_lo);
		if(compab_desc2->desc_type == SDTT_COMPAB_DESC_TYPE_HW)
		{
			if(module != SYS_HW_MODEL)
				return 0;
	
			if(version != SYS_HW_VERSION)
				return 0;
		}
		else if(compab_desc2->desc_type == SDTT_COMPAB_DESC_TYPE_SW)
		{
			if(module != SYS_SW_MODEL)
				return 0;
	
			if(version != SYS_SW_VERSION)
				return 0;
		}
		else
			return 0; //Unknown desc type
	
		compab_desc2 = (struct SDTT_COMPAB_DESC_2 *)(((UINT8 *)compab_desc2)
						+ compab_desc2->desc_len + 2);					
	}
	
	return CompabLen;
}

INT32 si_sdtt_parser(UINT8 *section, INT32 length, 
	struct section_parameter *param)
{
	INT32 i,j;	// sec_offset;
	UINT16 current_ver;
	//UINT16 program_number;
	struct sdtt_section*info;
	struct sdtt_content *content;
	//struct program_map *maps;
	struct sdtt_section_info *s_info = (struct sdtt_section_info *)param->priv;	//??

	if (section==NULL) {
	//	s_info->map_counter = 0;
		return SI_SUCCESS;
	} 

	//get current version
	current_ver=SYS_SW_VERSION;


	info = (struct sdtt_section *)section;
	content = (struct sdtt_content *)(section+sizeof(struct sdtt_section));

	for(i=0;i<info->numer_of_content;i++)
	{
		UINT16 cont_desc_len,sche_desc_len,trg_ver,new_ver,sch_time_N;
		UINT32 down_desc_total_len,down_desc_pase_size;
		struct sch_time *sched_time;
		struct SDTT_DL_CONT_DESC_1 *down_desc;

		cont_desc_len = content->content_ds_len_lo|(((UINT16)content->content_ds_len_hi)<<4);
		sche_desc_len =  content->schedule_ds_len_lo|(((UINT16)content->schedule_ds_len_hi)<<4);
		sch_time_N = (sche_desc_len/sizeof(struct sch_time));
		down_desc_total_len = cont_desc_len - sche_desc_len;
		sched_time = (struct sch_time *)(((UINT8 *)content)+sizeof(struct sdtt_content));
		down_desc = (struct SDTT_DL_CONT_DESC_1 *)(((UINT8 *)sched_time)+sche_desc_len);

		for(down_desc_pase_size=0;down_desc_pase_size<down_desc_total_len;)
		{
			UINT16 desc_len;
			UINT8 *desc_point;
			
			if(down_desc->compab_flag!=1)
				goto NEXT_CONT; 	//I can't check the model inf, skip it... 

			desc_point = (((UINT8 *)down_desc) + sizeof(struct SDTT_DL_CONT_DESC_1));
			desc_len = si_sdtt_parser_compab_desc((struct SDTT_COMPAB_DESC_1 *)desc_point);

			if(desc_len==0)	//Error parsering Compatibility Desc table
				goto NEXT_CONT;

			down_desc_pase_size += (sizeof(struct SDTT_DL_CONT_DESC_1) + desc_len);
			desc_point += desc_len;

			if(down_desc->mod_inf_flag==1)
			{				
				desc_len = st_sdtt_parser_module_desc(desc_point);
				down_desc_pase_size += desc_len;
				desc_point += desc_len;
			}

			//Private data
			desc_len = (*desc_point);
			desc_point += (desc_len+1);
			down_desc_pase_size += (desc_len+1);

			//text info
			if(down_desc->txt_inf_flag==1)
			{
				desc_point += 3;	//3 Bytes, ISO_639_Lang_code
				desc_len = (*desc_point);
				desc_point += (desc_len+1);
				down_desc_pase_size += (desc_len+1+3);
			}

			down_desc = (struct SDTT_DL_CONT_DESC_1 *)desc_point;	//Point to next download cont desc...			
		}

		//check version
		trg_ver = SDTT_MERG_UINT16(content->target_ver_hi,content->target_ver_lo);
		new_ver = SDTT_MERG_UINT16(content->new_ver_hi,content->new_ver_lo);
		
		switch(content->ver_indicator)
		{
			case SDTT_VER_INDICAT_ALL:
				//Do Nothing...
				break;
		
			case SDTT_VER_INDICAT_LATER:
				if(trg_ver<current_ver)
					goto NEXT_CONT;

				break;
		
			case SDTT_VER_INDICAT_EARLIER:
				if(current_ver<trg_ver)
					goto NEXT_CONT;

				break;
		
			case SDTT_VER_INDICAT_ONLY:
				if(trg_ver!=current_ver)
					goto NEXT_CONT;

				break;
		}

		{
			//Set Timer
			date_time dtSet,dtGet;	
			UINT32 mjd_time,set_dur_time,get_dur_time = 0,fForce;
			UINT8 temp;
			P_NODE p_node;
			T_NODE t_node;

			fForce = content->download_level;

			if(sch_time_N>0)
			{
				for(j=0;j<sch_time_N;j++)
				{
					#define BCD2DEC(a)		((a>>4)*10+(a&0x0F))

					mjd_time =(	(((UINT32)sched_time[j].sch_time_start[0])<<8) |
								(((UINT32)sched_time[j].sch_time_start[1])) );

					dtSet.hour = BCD2DEC(sched_time[j].sch_time_start[2]);
					dtSet.min = BCD2DEC(sched_time[j].sch_time_start[3]);
					dtSet.sec = BCD2DEC(sched_time[j].sch_time_start[4]);

					set_dur_time =(	(((UINT32)sched_time[j].sch_time_duration[0])<<16) |
								(((UINT32)sched_time[j].sch_time_duration[1])<<8) |
								(((UINT32)sched_time[j].sch_time_duration[2])) );						

					mjd_to_ymd(mjd_time,&dtSet.year,&dtSet.month,&dtSet.day,&temp);

					// God!!! Why directly call UI API?!
				//	api_ota_check_timerinfo(&dtSet,&set_dur_time,&fForce);

					dtGet = dtSet;
					get_dur_time = set_dur_time;
				}
			}
			else
			{
				//Update Now...
				get_local_time(&dtSet);
				convert_time_by_offset2(&dtGet,&dtSet,0,0,3);	//Set time as 3 second later...
				get_dur_time = 1;
			}

			if (get_prog_at(m_SdttChanIndex, &p_node) != SUCCESS)
				return SI_SUCCESS;
			
			get_tp_by_id(p_node.tp_id, &t_node);

			// God!!!
		//	sys_data_set_ota_band(t_node.bandwidth*1000);
		//	sys_data_set_ota_freq(t_node.frq);

		//	api_ota_timer_open(dtGet,get_dur_time,fForce);
		}		
	
NEXT_CONT:
		content = (struct sdtt_content *)((UINT8 *)content + sizeof(struct sdtt_content) + cont_desc_len);		
	}



	#if 0	
	info->numer_of_content=*(section+sizeof(struct section_header)+6); //get number of content
	sec_offset=sizeof(struct section_header)+7;	//move to start of content 
	for(i=0;  i<info->numer_of_content; i++)
	{
		content=(struct sdtt_content *)(section+sec_offset);	
		//if (SI_MERGE_UINT16(content->group) ==0x1234) //match group?
		{
			//-->It should be fixed!!
			if (( (current_ver <=(SI_MERGE_UINT16(content->target_ver_hi))) && (content->ver_indicator)==2) ||

			((current_ver >=(SI_MERGE_UINT16(content->target_ver_hi))) && (content->ver_indicator)==1) ||
			((current_ver ==(SI_MERGE_UINT16(content->target_ver_hi))) && (content->ver_indicator)==3) ||
			((content->ver_indicator)==0)  )
			{
				// match download
				
				// start to get schedule information
				
			}	
	    	}
		
		sec_offset+=(4+SI_MERGE_UINT16(content->schedule_ds_len_hi));
	}
	#endif

	return SI_SUCCESS;
}

